﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Opennav.MapGenerator
{
    public class BitWriter
    {
        static int INIT_BUFFER_SIZE = 8;
        static int INC_BUFFER_SIZE = 8;
        byte[] buffer;
        int bits = 0;

        public BitWriter()
        {
            buffer = new byte[INIT_BUFFER_SIZE];
        }

        public void Write(uint value, int nBits)
        {
            Ensure(bits + nBits);
            value = value & (uint)((1 << nBits) - 1);
            while (nBits > 0)
            {
                int byteOffset = bits / 8;
                int bitOffset = bits % 8;
                buffer[byteOffset] = (byte)(buffer[byteOffset] | ((value << bitOffset) & 0xff));
                int n = 8 - bitOffset;
                value = value >> n;
                if (n > nBits)
                    n = nBits;
                bits = bits + n;
                nBits = nBits - n;
            }
        }

        public void WriteBit(uint value)
        {
            Ensure(bits + 1);
            int byteOffset = bits / 8;
            int bitOffset = (bits % 8);
            buffer[byteOffset] = (byte)(buffer[byteOffset] | ((value & 0x1) << bitOffset));
            bits++;
        }

        public int Length { get { return (bits + 7) / 8; } }

        public byte[] Data
        {
            get
            {
                byte[] result = new byte[Length];
                Array.Copy(buffer, result, Length);
                return result;
            }
        }

        private void Ensure(int bits)
        {
            if ((bits + 7) / 8 > buffer.Length)
            {
                byte[] newBuffer = new byte[buffer.Length + INC_BUFFER_SIZE];
                Array.Copy(buffer, newBuffer, buffer.Length);
                buffer = newBuffer;
            }
        }
    }
}
